﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Xml.Linq;

namespace CL2018_1.Model
{
    class Config
    {

        /// <summary>
        /// 台体类型
        /// </summary>
        public TaiType TaiType
        {
            get;
            set;
        }

        /// <summary>
        /// 是否是188h模式
        /// </summary>
        public bool Is188H
        {
            get;
            set;
        }

        /// <summary>
        /// 表位数
        /// </summary>
        public int Bws
        {
            get;
            set;
        }

        /// <summary>
        /// rs485通道数量
        /// </summary>
        public int Rs485Count
        {
            get;
            set;
        }

        /// <summary>
        /// 2018-1地址
        /// </summary>
        public string CL2018_1Address
        {
            get;
            set;
        }


        /// <summary>
        /// 303端口
        /// </summary>
        public int Power303Port
        {
            get;
            set;
        }

        /// <summary>
        /// 误差板端口
        /// </summary>
        public int[] Port_188
        {
            get;
            set;
        }

        /// <summary>
        /// 485端口映射表
        /// </summary>
        public Dictionary<int, int> RS485Ports
        {
            get;
            set;
        }

        XDocument xdoc = null;

        public Config()
        {
            this.RS485Ports = new Dictionary<int, int>();
            this.LoadConfig(this.GetConfigFilePath());
        }

        private void LoadConfig(string configFile)
        {
            try
            {
                //配置文件不存在，则从资源中导出
                if (File.Exists(configFile) == false)
                {
                    File.WriteAllText(configFile, Resource1.CL2018_1Device);
                }
                xdoc = System.Xml.Linq.XDocument.Load(configFile);
                //解析数据

                //设备数据解析
                XElement device = xdoc.Root.Element("Device");
                this.TaiType = (TaiType)(Enum.Parse(typeof(TaiType), this.getConfigValue(device, "TaiType", "单相台")));
                this.Is188H = bool.Parse(this.getConfigValue(device, "188H", "true"));
                this.Bws = int.Parse(this.getConfigValue(device, "BwCount", "48"));
                this.Rs485Count = int.Parse(this.getConfigValue(device, "RS485Count", "8"));
                this.CL2018_1Address = this.getConfigValue(device, "2018_1Address", "193.168.18.1");
                this.Power303Port = int.Parse(this.getConfigValue(device, "303Port", "32"));
                this.Port_188 = StringToIntArray(this.getConfigValue(device, "Wcb", "16"));

                //rs485通道解析
                XElement rs485 = xdoc.Root.Element("RS485");
                for (int i = 1; i <= this.Rs485Count; i++)
                {
                    int port = int.Parse(this.getConfigValue(rs485, "线路" + i, "通道" + i).Substring(2));
                    this.RS485Ports.Add(i, port);
                }
            }
            catch (Exception ex)
            {
                System.Windows.MessageBox.Show("错误信息:" + ex.Message);
            }
        }

        public bool Save()
        {
            string configFile = GetConfigFilePath();

            try
            {
                //保存台体信息
                XElement device = this.xdoc.Root.Element("Device");

                this.SetConfigValue(device, "TaiType", this.TaiType);
                this.SetConfigValue(device, "188H", this.Is188H.ToString());
                this.SetConfigValue(device, "BwCount", this.Bws);
                this.SetConfigValue(device, "RS485Count", this.Rs485Count);
                this.SetConfigValue(device, "2018_1Address", this.CL2018_1Address);
                this.SetConfigValue(device, "303Port", this.Power303Port);
                this.SetConfigValue(device, "Wcb", ArrayToString(this.Port_188));

                //保存 485信息
                XElement rs485 = this.xdoc.Root.Element("RS485");
                rs485.RemoveNodes();
                foreach (KeyValuePair<int, int> key in this.RS485Ports)
                {
                    this.SetConfigValue(rs485, "线路" + key.Key, "通道" + key.Value);
                }

                this.xdoc.Save(configFile);
                return true;
            }
            catch (Exception ex)
            {
                System.Windows.MessageBox.Show("保存失败:" + ex.Message);
                return false;
            }
        }

        /// <summary>
        /// 获取配置文件路径
        /// </summary>
        /// <returns></returns>
        private string GetConfigFilePath()
        {
            string filePath = new FileInfo(this.GetType().Assembly.Location).DirectoryName + "\\CL2018_1Device.xml";
            return filePath;
        }

        private string getConfigValue(XElement xe, string key, string defaultValue)
        {
            try
            {
                return (from element in xe.Descendants()
                        where element.Attribute("Name").Value == key
                        select element)
                        .First().Attribute("Value").Value;
            }
            catch { return defaultValue; }
        }

        private void SetConfigValue(XElement xe, string key, object value)
        {
            try
            {
                XElement child = (from element in xe.Descendants()
                                  where element.Attribute("Name").Value == key
                                  select element).First();

            }
            catch
            {
                xe.Add(new XElement("Item", new XAttribute("Name", key), new XAttribute("Value", value.ToString())));
                return;
            }

            XAttribute attr = (from element in xe.Descendants()
                               where element.Attribute("Name").Value == key
                               select element)
                        .First().Attribute("Value");
            attr.Value = value.ToString();
        }

        /// <summary>
        /// 根据表位号获取 对应的 188端口
        /// </summary>
        /// <param name="bwh"></param>
        /// <returns></returns>
        public int Get188Port(int bwh)
        {
            //如果是广播，则返回第一个误差板，端口，
            //不支持在多条线路上，同时广播
            if (bwh == 0xFF)
            {
                return ChannelToPort(this.Port_188[0]);
            }

            //一个误差板的线管几个表位，
            int oneWcbLoadBws = this.Bws / this.Port_188.Length;
            int portIndex = (bwh + oneWcbLoadBws - 1) / oneWcbLoadBws - 1;
            return ChannelToPort(this.Port_188[portIndex]);
        }

        /// <summary>
        /// 根据表位号获取 对应的 端口
        /// </summary>
        /// <param name="bwh"></param>
        /// <returns></returns>
        public int Get485Port(int bwh)
        {
            int oneBusLoadBws = this.Bws / this.Rs485Count;
            int ChannelId = (bwh + oneBusLoadBws - 1) / oneBusLoadBws;
            if (ChannelId > this.RS485Ports.Keys.Count)
                ChannelId = this.RS485Ports.Keys.Count - 1;
            return ChannelToPort(this.RS485Ports[ChannelId]);
        }

        /// <summary>
        /// 通道转化为端口
        /// </summary>
        /// <param name="ChannelNo"></param>
        /// <returns></returns>
        private static int ChannelToPort(int ChannelNo)
        {
            const int CONST_DEFPORT = 20000;
            return CONST_DEFPORT + (ChannelNo - 1) * 2;
        }

        public static string ArrayToString(int[] ar)
        {
            string szTmp = string.Empty;
            for (int i = 0; i < ar.Length; i++)
                szTmp += string.Format("{0}|", ar[i]);
            if (szTmp.Length > 0) return szTmp.Substring(0, szTmp.Length - 1);
            return string.Empty;
        }

        public static int[] StringToIntArray(string szData)
        {
            if (szData.Length > 0 && szData[szData.Length - 1] == '|')
                szData = szData.Substring(0, szData.Length - 1);
            string[] ar = szData.Split(new char[] { '|' }, StringSplitOptions.RemoveEmptyEntries);
            int[] arInt = new int[ar.Length];
            for (int i = 0; i < ar.Length; i++)
                int.TryParse(ar[i], out arInt[i]);
            return arInt;
        }

    }
}
